<template>
	<!-- @submit.native.prevent 防止表单的输入框回车时刷新整个页面 -->
	<el-form v-bind="$attrs" :inline="ctx.newInline" label-width="auto" ref="elFormRef" scroll-to-error
		:validate-on-rule-change="false" :class="[ctx.widthClass, ctx.PaddingClass]" :rules="ctx.formRules"
		@submit.native.prevent>
		<el-button style="float: left; position: absolute; z-index: 10;" text @click="showConfigDailog = true"
			v-if="formId && loginInfo.userId == 1300000000101"></el-button>
		<slot> </slot>
	</el-form>
	<el-dialog v-if="formId && loginInfo.userId == 1300000000101" v-model="showConfigDailog" width="1000px" draggable>
		<template #header>
			<div style="color: #fff">
				<span>表单配置</span>
			</div>
		</template>
		<el-form label-width="auto">
			<el-form-item label="表单名称">
				<el-input v-model="ctx.formTitle"></el-input>
			</el-form-item>
			<el-row v-for="item in ctx.ruleConfig">
				<el-form-item :label="item.prop">
					<el-input v-model="item.label"></el-input>
				</el-form-item>
				<el-form-item label="是否必填">
					<el-switch v-model="item.required"></el-switch>
				</el-form-item>
				<el-form-item label="默认值">
					<el-input v-model="item.default"></el-input>
				</el-form-item>
				<el-form-item label=""></el-form-item>
			</el-row>
		</el-form>
		<template #footer>
			<slot name="footer">
				<el-button @click="resetLabel"> 恢复原始label</el-button>
				<el-button @click="showConfigDailog = false"> 取 消</el-button>
				<el-button @click="submitFormConfig" type="primary"> 保 存</el-button>
			</slot>
		</template>
	</el-dialog>
</template>

<script lang="ts">
export interface RuleConfig {
	prop: string;
	label: string;
	required: boolean;
	trigger?: string;
	default: string;
}
</script>
<script lang="ts" setup>
// 可配置必填项的表单, 也支持配置默认值和label: 需要子组件主动调用 getDefault 和 getLabel 方法
// 使用: <MkForm :model="ctx.entity" ref="formRef" formId="productLine"> </MkForm>
import { onMounted, ref, watch } from 'vue';
import type { FormInstance, FormValidationResult, FormItemProp, FormRules, FormValidateCallback } from 'element-plus'
import type { Arrayable } from 'element-plus/es/utils';
import { BasFormConfigInput } from '/@/api/bas/BasFormConfig';
import { getFormConfig, loginInfo, saveFormConfig } from '/@/stores/baseInfo/';
import { clog, isNull } from '/@/utils'

defineOptions({
	name: 'MkForm'
})

const props = defineProps({
	formId: {
		type: String,
	},
	inline: {
		type: Boolean,
		default: undefined,
	},
	col: {
		// 表单列数,最多设置为3,适用性更好, 特殊情况可以设置为4
		type: Number,
		default: 1,
	},
});

//const rules = { account: [{ required: true, message: '用户名必填', trigger: 'blur' }],	password: [{ required: true, message: '密码必填', trigger: 'blur' }] },
const showConfigDailog = ref(false);
const elFormRef = ref<FormInstance>();
const ctx = reactive({
	formTitle: '',
	formRules: {} as FormRules,  // 表单的rules
	ruleConfig: [] as RuleConfig[], // 表单的配置
	widthClass: 'width-1',
	PaddingClass: 'pbottom',
	newInline: false as boolean | undefined, // 是否inline,
});

// 构造ruleConfig
onMounted(async () => {
	if (isNull(props.inline)) {
		// 只有一列的时候设置为非inline, 其他情况都设置为inline
		ctx.newInline = (props.col == 1 ? false : true)
	} else {
		// 如果传入了inline, 则使用传入的inline
		ctx.newInline = props.inline
	}

	if (ctx.newInline) {
		ctx.PaddingClass = "pbottom0"
	} else {
		ctx.PaddingClass = "pbottom"
	}

	switch (props.col) {
		case 1:
			ctx.widthClass = 'width-1';
			break;
		case 2:
			ctx.widthClass = 'width-2';
			break;
		case 3:
			ctx.widthClass = 'width-3';
			break;
		case 4:
			ctx.widthClass = 'width-4';
			break;
	}

	if (props.formId) {
		let ruleConfigInStore = await getFormConfig("form", props.formId); // 获取表单必填配置
		let FormConfig = []; //必填项配置数组
		if (ruleConfigInStore.config && ruleConfigInStore.config.items) {
			FormConfig = ruleConfigInStore.config.items
		}
		ctx.formTitle = ruleConfigInStore.title;
		// 遍历所有字段构造ruleConfig
		elFormRef.value?.fields.forEach((item) => {
			var required = false;
			var label = item.label;
			var defaultValue = "";
			// 从缓存中获取是否必填
			FormConfig.forEach((i2: RuleConfig) => {
				if (item.prop == i2.prop) {
					required = i2.required;
					label = i2.label;
					defaultValue = i2.default;
				}
			});
			ctx.ruleConfig.push({ prop: item.prop as string, label: label as string, required: required, default: defaultValue })
		});
	}
});

// 通过ruleConfig构造表单的rules
watch(ctx.ruleConfig, (newValue, oldValue) => {
	ctx.ruleConfig.forEach(item => {
		if (isNull(item.prop)) {
			return;
		}
		ctx.formRules[item.prop] = [{ required: item.required, message: `${item.label ?? item.prop}不能为空` }]
	});
})

// 恢复原始label
const resetLabel = () => {
	ctx.ruleConfig.forEach((i2: RuleConfig) => {
		elFormRef.value?.fields.forEach((item) => {
			if (item.prop == i2.prop) {
				i2.label = item.label as string;
			}
		});
	});
};

// 保存表单配置, TODO 保存表单的宽度,背景色,标题等其他配置
const submitFormConfig = async () => {
	let input = { id: props.formId, tag: 'form', title: ctx.formTitle, config: { items: ctx.ruleConfig, form: {} } }
	await saveFormConfig(input as BasFormConfigInput);
	showConfigDailog.value = false;
}


// 表单验证  (callback?: FormValidateCallback) => Promise<void>
// 举例:
// const validate = await mkFormRef?.value.validate();
// if (!validate) return;
const validate = async (callback?: FormValidateCallback): FormValidationResult => {
	let validateBoolean = await elFormRef?.value?.validate(callback) ?? true;
	return validateBoolean
}

// 重置该表单项，将其值重置为初始值，并移除校验结果
const resetFields = (props?: Arrayable<FormItemProp>) => {
	elFormRef.value?.resetFields(props);
}

// 清理某个字段的表单验证信息。
const clearValidate = (props?: Arrayable<FormItemProp>) => {
	elFormRef.value?.clearValidate(props);
}

const scrollToField = (prop: FormItemProp) => {
	return elFormRef.value?.scrollToField(prop);
}

/** 获取默认值
用法举例: 
setTimeout(() => { // 必须异步加载,否则 getDefault 会不存在
	if (isNull(row)) { // 必须是新增的时候主动调用
		ctx.entity.shortName = formRef?.value.getDefault("shortName");
	}
}
 */
const getDefault = (prop: string) => {
	for (var i = 0; i < ctx.ruleConfig.length; i++) {
		if (prop == ctx.ruleConfig[i].prop) {
			return ctx.ruleConfig[i].default;
		}
	}
	return "";
}

/** 获取label, 相当于label多语言, 
 * 给没有启用多语言的标签使用
 * 不推荐使用此方法, 推荐用多语言, 
用法举例: 
setTimeout(() => { // 必须异步加载,否则 getLabel 会不存在
	let label = formRef.value.getLabel('shortName')
	labelShortName.value = isNull(label) ? '简称' : label;
}
 */
const getLabel = (prop: string) => {
	for (var i = 0; i < ctx.ruleConfig.length; i++) {
		if (prop == ctx.ruleConfig[i].prop) {
			return ctx.ruleConfig[i].label;
		}
	}
	return "";
}

defineExpose({ validate, getDefault, getLabel, resetFields, clearValidate, scrollToField, elFormRef })

</script>
<style lang='scss' scoped>
.width-1 {
	max-width: 500px;
}

.width-2 {
	max-width: 700px;
}

.width-3 {
	max-width: 1050px;
}

.width-4 {
	max-width: 1400px;
}

.pbottom {
	padding-bottom: 10px;
}

.pbottom0 {
	padding-bottom: 0px;
}
</style>
